package cc.rengu.redp.flowable.bizmodel.web.service.impl;

import cc.rengu.redp.common.domain.QueryRequest;
import cc.rengu.redp.common.utils.SortUtil;
import cc.rengu.redp.flowable.bizmodel.db.dao.BizDataMapper;
import cc.rengu.redp.flowable.bizmodel.db.domain.BizCfgField;
import cc.rengu.redp.flowable.bizmodel.db.domain.BizData;
import cc.rengu.redp.flowable.bizmodel.domain.BizDataQueryConditions;
import cc.rengu.redp.flowable.bizmodel.db.domain.BizIndex;
import cc.rengu.redp.flowable.bizmodel.web.service.BizCfgFieldService;
import cc.rengu.redp.flowable.bizmodel.web.service.BizDataService;
import cc.rengu.redp.flowable.bizmodel.web.service.BizIndexService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author System
 */
@Service
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class BizDataServiceImpl extends ServiceImpl<BizDataMapper, BizData> implements BizDataService {

    @Autowired
    private BizCfgFieldService bizCfgFieldService;

    @Autowired
    private BizIndexService bizIndexService;

    public BizData getOneByUniqKey(String uniqKey) {
        LambdaQueryWrapper<BizData> lambdaQueryWrapper = new LambdaQueryWrapper();
        lambdaQueryWrapper.eq(BizData::getUniqKey, uniqKey);
        return this.baseMapper.selectOne(lambdaQueryWrapper);
    }

    @Override
    public IPage<BizData> findBizDataList(QueryRequest request, String modelId, List<BizDataQueryConditions> conditions) {
        try {
            if (conditions.size() > 0) {
                //获取模型字段列表
                List<BizCfgField> bizCfgFields = bizCfgFieldService
                        .getBaseMapper()
                        .selectList((new LambdaQueryWrapper<BizCfgField>()).eq(BizCfgField::getModelId, modelId));

                //条件分组
                Map<String, List<BizDataQueryConditions>> grpConditions = new HashMap<>();
                conditions.forEach(con -> {
                    List<BizDataQueryConditions> bizDataQueryConditions = grpConditions.get(con.getQueryField());
                    if (bizDataQueryConditions == null) {
                        List<BizDataQueryConditions> list = new ArrayList<>();
                        list.add(con);
                        grpConditions.put(con.getQueryField(), list);
                    } else {
                        bizDataQueryConditions.add(con);
                    }
                });

                // 组装lambda查询条件
                // 组装SQL查询：(MODEL_ID = ? AND ((FIELD_NAME = ? AND FIELD_VALUE_STRING = ?) OR (FIELD_NAME = ? AND FIELD_VALUE_STRING = ? AND FIELD_VALUE_STRING = ?)))
                // GROUP BY DATA_ID HAVING COUNT(DATA_ID) = n
                LambdaQueryWrapper<BizIndex> lqwBizIndex = new LambdaQueryWrapper<>();
                lqwBizIndex.select(BizIndex::getDataId);
                lqwBizIndex.eq(BizIndex::getModelId, modelId).and(i ->
                        grpConditions.entrySet().stream().forEach(entry -> {
                        //获取模型字段配置
                        List<BizCfgField> rs = bizCfgFields
                                .stream()
                                .filter((BizCfgField b) -> b.getFieldName().equals(entry.getKey()))
                                .collect(Collectors.toList());
                        if (rs.size() != 1) return;
                        i.or (p -> {
                            if ("String".equals(rs.get(0).getFieldType())) {
                                p.eq(BizIndex::getFieldName, entry.getKey());
                                entry.getValue().forEach(con -> {
                                    switch (con.getOperator()){
                                        case "=" : p.eq(BizIndex::getFieldValueString, con.getQueryValue());break;
                                        case "like" : p.likeRight(BizIndex::getFieldValueString, con.getQueryValue());break;
                                        case ">" : p.gt(BizIndex::getFieldValueString, con.getQueryValue());break;
                                        case ">=" : p.ge(BizIndex::getFieldValueString, con.getQueryValue());break;
                                        case "<" : p.lt(BizIndex::getFieldValueString, con.getQueryValue());break;
                                        case "<=" : p.le(BizIndex::getFieldValueString, con.getQueryValue());break;
                                    }
                                });
                            } else if ("Date".equals(rs.get(0).getFieldType())) {
                                p.eq(BizIndex::getFieldName, entry.getKey());
                                entry.getValue().forEach(con -> {
                                    switch (con.getOperator()){
                                        case "=": p.eq(BizIndex::getFieldValueDate, LocalDate.parse(con.getQueryValue()));break;
                                        case ">": p.gt(BizIndex::getFieldValueDate, LocalDate.parse(con.getQueryValue()));break;
                                        case ">=": p.ge(BizIndex::getFieldValueDate, LocalDate.parse(con.getQueryValue()));break;
                                        case "<": p.lt(BizIndex::getFieldValueDate, LocalDate.parse(con.getQueryValue()));break;
                                        case "<=": p.le(BizIndex::getFieldValueDate, LocalDate.parse(con.getQueryValue()));break;
                                    }
                                });
                            }
                        });
                    })
                );

                lqwBizIndex.groupBy(BizIndex::getDataId).having("COUNT(DATA_ID) = " + grpConditions.size());
                Page<BizIndex> page = new Page<>();
                SortUtil.handlePageSort(request, page, true);
                //查询索引表
                IPage<BizIndex> bizIndexPage = bizIndexService.page(page, lqwBizIndex);

                //查询业务表
                LambdaQueryWrapper<BizData> lqwBizData = new LambdaQueryWrapper();
                List<Long> dataIds = new ArrayList<>();
                bizIndexPage.getRecords().forEach(bizIndex -> dataIds.add(bizIndex.getDataId()));
                List<BizData> bizDataList = new ArrayList<>();
                if (dataIds.size() != 0){
                    lqwBizData.in(BizData::getDataId, dataIds);
                    bizDataList.addAll(this.list(lqwBizData));
                }
                IPage<BizData> ipBizData = new Page<>();
                ipBizData.setRecords(bizDataList);
                ipBizData.setCurrent(bizIndexPage.getCurrent());
                ipBizData.setSize(bizIndexPage.getSize());
                ipBizData.setPages(bizIndexPage.getPages());
                ipBizData.setTotal(bizIndexPage.getTotal());
                return ipBizData;
            } else {
                LambdaQueryWrapper<BizData> lqwBizData = new LambdaQueryWrapper<>();
                lqwBizData.eq(BizData::getModelId, modelId);
                Page<BizData> page = new Page<>();
                SortUtil.handlePageSort(request, page, true);
                return this.page(page, lqwBizData);
            }
        } catch (Exception e) {
            log.error("获取业务数据失败", e);
            return null;
        }
    }
}
